"""
异步音频处理业务逻辑服务
"""
import time
from typing import Tuple, Optional
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import UploadFile
from loguru import logger

from app.databases.schemas import AudioProcessingRecordCreate, AudioProcessingRecordUpdate
from app.repositories.audio_repository_async import AsyncAudioProcessingRepository
from app.utils.audio_utils import (
    validate_audio_file, 
    process_audio_pitch_shift,
    get_audio_info,
    format_processing_time
)
from app.core.config import settings
from app.core.exceptions import (
    AudioProcessingException, 
    InvalidPitchStepsException
)


class AudioProcessingService:
    """异步音频处理服务"""
    
    def __init__(self, db: AsyncSession):
        self.db = db
        self.audio_repo = AsyncAudioProcessingRepository(db)
    
    async def process_audio(
        self, 
        file: UploadFile, 
        n_steps: int,
        user_id: Optional[int] = None
    ) -> Tuple[bytes, dict]:
        """
        处理音频文件
        
        Args:
            file: 上传的音频文件
            n_steps: 音调调节步数
            user_id: 用户ID（可选）
        
        Returns:
            Tuple[bytes, dict]: 处理后的音频数据和记录信息
        
        Raises:
            InvalidPitchStepsException: 无效的音调步数
            AudioProcessingException: 音频处理失败
        """
        # 验证参数
        if not -24 <= n_steps <= 24:
            raise InvalidPitchStepsException()
        
        # 验证文件
        validate_audio_file(file, settings.MAX_FILE_SIZE)
        
        # 读取文件数据
        audio_data = await file.read()
        
        # 创建处理记录
        record_data = AudioProcessingRecordCreate(
            filename=file.filename or "unknown",
            file_size=len(audio_data),
            file_type=file.content_type or "unknown",
            pitch_steps=n_steps,
            status="processing"
        )
        
        record = await self.audio_repo.create(record_data.model_dump())
        
        start_time = time.time()
        
        try:
            # 处理音频
            processed_audio, sample_rate = process_audio_pitch_shift(
                audio_data, n_steps
            )
            
            # 计算处理时间
            processing_time = time.time() - start_time
            
            # 更新记录状态
            update_data = AudioProcessingRecordUpdate(
                processing_time=processing_time,
                status="completed"
            )
            
            await self.audio_repo.update(record, update_data.model_dump())
            
            # 准备返回信息
            result_info = {
                "record_id": record.id,
                "filename": file.filename,
                "processing_time": format_processing_time(processing_time),
                "status": "completed",
                "sample_rate": sample_rate,
                "output_size": len(processed_audio)
            }
            
            return processed_audio, result_info
            
        except Exception as e:
            # 更新失败状态
            processing_time = time.time() - start_time
            update_data = AudioProcessingRecordUpdate(
                processing_time=processing_time,
                status="failed",
                error_message=str(e)
            )
            
            await self.audio_repo.update(record, update_data.model_dump())
            
            logger.error(f"音频处理失败: {str(e)}")
            raise AudioProcessingException(f"音频处理失败: {str(e)}")
    
    async def get_processing_record(self, record_id: int) -> Optional[dict]:
        """
        获取处理记录
        
        Args:
            record_id: 记录ID
        
        Returns:
            Optional[dict]: 处理记录信息
        """
        record = await self.audio_repo.get(record_id)
        if record:
            return {
                "id": record.id,
                "filename": record.filename,
                "file_size": record.file_size,
                "file_type": record.file_type,
                "pitch_steps": record.pitch_steps,
                "processing_time": record.processing_time,
                "status": record.status,
                "error_message": record.error_message,
                "created_at": record.created_at,
                "updated_at": record.updated_at
            }
        return None
    
    async def get_recent_records(self, limit: int = 10) -> list:
        """
        获取最近的处理记录
        
        Args:
            limit: 记录数量限制
        
        Returns:
            list: 处理记录列表
        """
        records = await self.audio_repo.get_recent_records(limit)
        return [
            {
                "id": record.id,
                "filename": record.filename,
                "pitch_steps": record.pitch_steps,
                "status": record.status,
                "processing_time": record.processing_time,
                "created_at": record.created_at
            }
            for record in records
        ]
    
    async def get_statistics(self) -> dict:
        """
        获取处理统计信息
        
        Returns:
            dict: 统计信息
        """
        return await self.audio_repo.get_statistics()
    
    def get_audio_info(self, audio_data: bytes) -> dict:
        """
        获取音频文件信息
        
        Args:
            audio_data: 音频数据
        
        Returns:
            dict: 音频信息
        """
        try:
            return get_audio_info(audio_data)
        except Exception as e:
            logger.error(f"获取音频信息失败: {str(e)}")
            raise AudioProcessingException(f"获取音频信息失败: {str(e)}")
    
    async def get_processing_trends(self, days: int = 7) -> list:
        """
        获取处理趋势数据
        
        Args:
            days: 天数
        
        Returns:
            list: 趋势数据
        """
        return await self.audio_repo.get_processing_trends(days)
    
    async def get_average_processing_time(self) -> Optional[float]:
        """
        获取平均处理时间
        
        Returns:
            Optional[float]: 平均处理时间
        """
        return await self.audio_repo.get_average_processing_time()
    
    async def cleanup_old_records(self, days: int = 30) -> int:
        """
        清理旧记录
        
        Args:
            days: 保留天数
        
        Returns:
            int: 清理的记录数
        """
        return await self.audio_repo.cleanup_old_records(days)
